/*  File Name	: Sock.cpp
 *  Author		: Pang Jiacai
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-4-20
 *  Description:
 */

#include "Sock.h"
#include "EventHandler.h"

Sock::Sock()
{
	this->handle_ = -1;
}

Sock::Sock(int pro_family,int type,int protocol,bool reuseaddr)
{
	this->handle_ = -1;
	this->open(pro_family,type,protocol,reuseaddr);
}

Sock::~Sock()
{

}

int Sock::open(int pro_family,int type,int protocol,bool reuseaddr)
{
	this->handle_ = ::socket(pro_family,type,protocol);
	if (handle_ < 0)
	{
		LOG((DEBUG_LOG,"Sock::open socket() error:%s",strerror(errno)));
		return -1;
	}

	if (reuseaddr)
	{
		if(this->set_sockopt(SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int))!=0)
		{
			LOG((DEBUG_LOG,"Sock::open-->set_sockopt error:%s",strerror(errno)));
			::close(handle_);
			return -1;
		}
	}
	return 0;
}

int Sock::close(void)
{
	int ret = 0;
	if(this->handle_!=INVALID_HANDLER)
	{
		LOG((DEBUG_LOG,"Sock::close[%d]",this->handle_));
		ret = ::close(this->handle_);
		this->handle_ = INVALID_HANDLER;
	}
	return ret;
}

int Sock::set_sockopt(int level,int option,void *optval,int optlen)
{
	return ::setsockopt(handle_,level,option,optval,optlen);
}

const int Sock::get_sockopt(int level,int option,void *optval,int *optlen)
{
	return ::getsockopt(handle_,level,option,optval,(socklen_t*)optlen);
}

int Sock::enable(int flag)
{
	switch(flag)
	{
		case O_CLOEXEC:
		{
			break;
		}
		case O_NONBLOCK:
		{
			int val = ::fcntl (handle_, F_GETFL, 0);
			if(val==-1)
			{
				return -1;
			}
			SET_BITS(val,flag);
			if(::fcntl(handle_,F_SETFL,val)==-1)
			{
				return -1;
			}
			return 0;
		}
		default:
			break;
	}
	return 0;
}

int Sock::disable(int flag)
{
	switch (flag)
	{
		case O_CLOEXEC:
		{
			break;
		}
		case O_NONBLOCK:
		{
			int val = ::fcntl(handle_, F_GETFL, 0);
			if (val == -1)
			{
				return -1;
			}
			CLR_BITS(val, flag);
			if (::fcntl(handle_, F_SETFL, val) == -1)
			{
				return -1;
			}
			return 0;
		}
		default:
			break;
	}
	return 0;
}

void Sock::set_handle(int handle)
{
	this->handle_ = handle;
}

int Sock::get_handle(void) const
{
	return this->handle_;
}

int Sock::get_remote_addr(sockaddr_in *addr) const
{
	socklen_t len = sizeof(sockaddr_in);
	return ::getpeername(this->handle_,(sockaddr*)addr,&len);
}

int Sock::get_local_addr(sockaddr_in *addr) const
{
	socklen_t len = sizeof(sockaddr_in);
	return ::getsockname(this->handle_,(sockaddr*)addr,&len);
}

std::string Sock::get_host(void) const
{
	sockaddr_in addr;;
	if (this->get_remote_addr(&addr)!=1)
	{
		return std::string(inet_ntoa(addr.sin_addr));
	}
	return "";
}

int Sock::get_port(void) const
{
	sockaddr_in addr;
	if(this->get_remote_addr(&addr)!=-1)
	{
		return ntohs(addr.sin_port);
	}
	return 0;
}
